home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1996 February / EnigmA AMIGA RUN 04 (1996)(G.R. Edizioni)(IT)[!][issue 1996-02][Skylink CD III].iso / earcd / library / shutdown.lzh / shutdown / src / shutdown.c < prev    next >
C/C++ Source or Header  |  1995-10-26  |  12KB  |  509 lines

  1. /*
  2.    shutdown.c --- shutdown command.
  3.  
  4.    (c) Copyright 1995 SHW Wabnitz
  5.    Written by Bernhard Fastenrath (fasten@shw.com)
  6.  
  7.    This file may be distributed under the terms
  8.    of the GNU General Public License.
  9. */
  10.  
  11. #include <dos.h>
  12. #include <stdio.h>
  13. #include <string.h>
  14. #include <stdlib.h>
  15. #include <exec/types.h>
  16. #include <exec/memory.h>
  17. #include <intuition/intuition.h>
  18. #include <proto/exec.h>
  19. #include <proto/intuition.h>
  20.  
  21. #include "queue/queue.h"
  22. #include "queue/shutdown.h"
  23. #include "shutdown_cmd.h"
  24. #include "shutdownbase.h"
  25.  
  26. #if defined (__GNUC__)
  27. #include "queue/queue_inline.h"
  28. #else
  29. #include "queue/queue_pragmas.h" /* Not yet */
  30. #endif
  31.  
  32. #if defined (__GNUC__)
  33. #include "shutdown_inline.h"
  34. #else
  35. #include "shutdown_pragmas.h" /* Not yet */
  36. #endif
  37.  
  38. #define SIGBREAKF_MASK ( SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_D | \
  39.              SIGBREAKF_CTRL_E | SIGBREAKF_CTRL_F )
  40.  
  41. int GoDown (int time);
  42. void CleanUp (char *error);
  43. ShutdownMessage *BroadcastShutdownMsg (ULONG status, ULONG time);
  44.  
  45. struct IntuitionBase *IntuitionBase = NULL;
  46. struct Library *QueueBase = NULL;
  47. struct Library *ShutdownBase = NULL;
  48. struct timerequest *TimerReq = NULL;
  49. struct MsgPort *TimerPort = NULL;
  50. struct MsgPort *ShutdownPort = NULL;
  51. QHandle ShutdownHandle = NULL;
  52. ULONG TimerMask;
  53. ULONG TimerErr = 1;
  54. ULONG ShutdownMask;
  55. ULONG WaitMask;
  56. ULONG QueueSignal, QueueMask;
  57. int point_of_no_return = 0;
  58. char *ShutdownPortname = "Shutdown";
  59. int SpNameLen;
  60. char *CantAllocatePort = "Can't allocate signal or message port.\n";
  61. char *ShutdownCancelled = "shutdown cancelled.\n";
  62. char *OutOfMemory = "Out of memory.\n";
  63. char *SorryTooLate = "Too late to stop shutdown.\n";
  64. int MessageTimedOut = 0;
  65. int HaltFlag = HFLG_HALT;
  66. int SyncTime = 5;
  67. int UseShutdownLibFlag = 0;
  68. int AbortableFlag = 1;
  69. int FastBoot = 0;
  70. int UnmountMode = UMNT_INHIBIT;
  71. int Error;
  72. char *optarg = NULL;
  73.  
  74. int
  75. getopt (int argc, char *argv[], char *opts)
  76. {
  77.   static int pos = 0;
  78.   char *c;
  79.  
  80.   while (++pos < argc && argv[pos][0] != '-');
  81.   if (pos >= argc)
  82.     return -1;
  83.   if ((c = strchr (opts, (int) argv[pos][1])) == 0)
  84.     return (int) '?';
  85.   if (*(c+1) != ':')
  86.     return (int) *c;
  87.   if (strlen (argv[pos]) > 2)
  88.     optarg = argv[pos] + 2;
  89.   else if (pos+1 < argc)
  90.     optarg = argv[pos+1];
  91.   else
  92.     return (int) '?';
  93.   return (int) *c;
  94. }
  95.  
  96. ULONG
  97. PutAndGet (Message *msg, char *portname)
  98. {
  99.   struct MsgPort *prt, *reply_port;
  100.   ULONG error;
  101.  
  102.   if (!(reply_port = CreateMsgPort ()))
  103.     return 1;
  104.   msg -> mn_ReplyPort = reply_port;
  105.  
  106.   Forbid ();
  107.   if (prt = FindPort (portname))
  108.   {
  109.     PutMsg (prt, msg);
  110.     Permit ();
  111.     do
  112.       WaitPort (reply_port);
  113.     while (!GetMsg (reply_port));
  114.   }
  115.   else
  116.     Permit ();
  117.  
  118.   DeleteMsgPort (reply_port);
  119.   return prt ? 0 : 2;
  120. }
  121.  
  122. void
  123. CancelRunningShutdown (void)
  124. {
  125.   Message *msg;
  126.  
  127.   if (!(msg = AllocMem (sizeof (Message), MEMF_PUBLIC | MEMF_CLEAR)))
  128.     CleanUp (OutOfMemory);
  129.  
  130.   switch (PutAndGet (msg, ShutdownPortname))
  131.   {
  132.     case 0:
  133.       if (msg -> mn_Node.ln_Name == (APTR) -1)
  134.         CleanUp (SorryTooLate);
  135.       CleanUp (ShutdownCancelled);
  136.     case 1:
  137.       CleanUp (CantAllocatePort);
  138.     case 2:
  139.       CleanUp ("Shutdown is not running.\n");
  140.   }
  141.   FreeMem (msg, sizeof (Message));
  142. }
  143.  
  144. void
  145. CleanUp (char *error)
  146. {
  147.   ShutdownMessage *msg;
  148.  
  149.   if (error)
  150.     printf (error);
  151.   if (!TimerErr)
  152.     CloseDevice ((struct IORequest *) TimerReq);
  153.   if (TimerReq)
  154.     DeleteIORequest (TimerReq);
  155.   if (TimerPort)
  156.     DeleteMsgPort (TimerPort);
  157.   if (ShutdownPort)
  158.   {
  159.     if (ShutdownPort -> mp_Node.ln_Name)
  160.       FreeMem (ShutdownPort -> mp_Node.ln_Name, SpNameLen);
  161.     RemPort (ShutdownPort);
  162.     DeleteMsgPort (ShutdownPort);
  163.   }
  164.   if (ShutdownHandle)
  165.   {
  166.     while (msg = (ShutdownMessage *) QGetMsg (ShutdownHandle))
  167.       FreeMem (msg, sizeof (ShutdownMessage));
  168.     if (QClose (ShutdownHandle))
  169.     {
  170.       printf ("Exiting, waiting for replies.\n");
  171.       while (QClose (ShutdownHandle) > 0)
  172.       {
  173.         Delay (50);
  174.         while (msg = (ShutdownMessage *) QGetMsg (ShutdownHandle))
  175.       FreeMem (msg, sizeof (ShutdownMessage));
  176.       }
  177.     }
  178.     FreeSignal (QueueSignal);
  179.   }
  180.   if (QueueBase)
  181.     CloseLibrary (QueueBase);
  182.   if (ShutdownBase)
  183.     CloseLibrary (ShutdownBase);
  184.   if (IntuitionBase)
  185.     CloseLibrary ((struct Library *) IntuitionBase);  
  186.   exit (error ? EXIT_FAILURE : EXIT_SUCCESS);
  187. }
  188.  
  189. int
  190. CancelShutdown (void)
  191. {
  192.   if (point_of_no_return)
  193.     return 0;
  194.  
  195.   BroadcastShutdownMsg (SHUTDOWN_ABORT, 0);
  196.   CleanUp (ShutdownCancelled);
  197. }
  198.  
  199. ShutdownMessage *
  200. GetShutdownMessage ()
  201. {
  202.   ShutdownMessage *sm;
  203.  
  204.   for (;;)
  205.   {
  206.     if (sm = (ShutdownMessage *) QGetMsg (ShutdownHandle))
  207.       break;
  208.     if (sm = (ShutdownMessage *)
  209.     AllocMem (sizeof (ShutdownMessage), MEMF_PUBLIC | MEMF_CLEAR))
  210.       break;
  211.     Delay (50);
  212.   }
  213.   return sm;
  214. }
  215.  
  216. ShutdownMessage *
  217. BroadcastShutdownMsg (ULONG status, ULONG time)
  218. {
  219.   ShutdownMessage *smsg;
  220.  
  221.   smsg = GetShutdownMessage ();
  222.   smsg -> sm_Status   = status;
  223.   smsg -> sm_TimeLeft = time;
  224.   QAddMsg (ShutdownHandle, (QMessage *) smsg);
  225.   return smsg;
  226. }
  227.  
  228. void
  229. AbortableDelay (int seconds)
  230. {
  231.   int abort = 0;
  232.   Message *msg;
  233.   ULONG mask;
  234.  
  235.   TimerReq -> tr_node.io_Command = TR_ADDREQUEST;
  236.   TimerReq -> tr_time.tv_secs  = seconds;
  237.   TimerReq -> tr_time.tv_micro = 0;
  238.   SendIO ((struct IORequest *) TimerReq);
  239.  
  240.   while (1)
  241.   {
  242.     mask = Wait (WaitMask);
  243.     if (mask & ShutdownMask)
  244.     {
  245.       do
  246.         WaitPort (ShutdownPort);
  247.       while (!(msg = (Message *) GetMsg (ShutdownPort)));
  248.       if (point_of_no_return || AbortableFlag == 0)
  249.     msg -> mn_Node.ln_Name = (APTR) -1;
  250.       else
  251.         abort = 1;
  252.       ReplyMsg ((struct Message *) msg);
  253.     }
  254.     if (mask & QueueMask)
  255.     {
  256.       /* Shutdown Queue reply: we aren't really interested
  257.          because we take our messages fresh from the reply
  258.      list when we need them.
  259.      The timer is still running so we just wait some more.
  260.       */
  261.     }
  262.     if (mask & SIGBREAKF_MASK || abort)
  263.     {
  264.       if (point_of_no_return)
  265.       {
  266.     printf (SorryTooLate);
  267.     continue;
  268.       }
  269.       if (!(mask & TimerMask))
  270.         AbortIO ((struct IORequest *) TimerReq);
  271.       WaitIO ((struct IORequest *) TimerReq);
  272.       SetSignal (0L, TimerMask);
  273.  
  274.       if (mask & SIGBREAKF_CTRL_C || abort)
  275.       {
  276.     if (mask & SIGBREAKF_CTRL_C)
  277.       printf ("CTRL-C\n");
  278.     CancelShutdown ();
  279.     printf ("Timer stopped, press CTRL-E or CTRL-F to reboot.\n");
  280.       }
  281.       if (mask & SIGBREAKF_CTRL_D) /* CTRL-D: speed up */
  282.       {
  283.     printf ("CTRL-D\n");
  284.     return;
  285.       }
  286.       if (!FastBoot)
  287.       {
  288.     FastBoot = 1;
  289.     if (mask & SIGBREAKF_CTRL_E) /* CTRL-E: fast reboot */
  290.         {
  291.       printf ("CTRL-E\n");
  292.       GoDown (5);
  293.         }
  294.     if (mask & SIGBREAKF_CTRL_F) /* CTRL-F: very fast reboot */
  295.     {
  296.       printf ("CTRL-F\n");
  297.       GoDown (0);
  298.     }
  299.       }
  300.       else
  301.     return;
  302.     }
  303.     if (mask & TimerMask) /* done waiting */
  304.       return;
  305.   }
  306. }
  307.  
  308. int
  309. GoingDownMessage (int seconds)
  310. {
  311.   if (seconds / 3600)
  312.     printf ("The system is going down in %d:%.2d hours.\n",
  313.             seconds / 3600, (seconds % 3600) / 60);
  314.   else if (seconds / 60)
  315.     printf ("The system is going down in %d:%.2d minutes.\n",
  316.             seconds / 60, seconds % 60);
  317.   else
  318.     printf ("The system is going down in %d seconds.\n", seconds);
  319. }
  320.  
  321. int
  322. main (int argc, char *argv[])
  323. {
  324.   int shutdown_time = 10, shutdown_interval;
  325.   int cancel_flag = 0;
  326.   int opt, rest;
  327.  
  328.   SetTaskPri (FindTask (0L), 10);
  329.  
  330.   /*** Options ***/
  331.  
  332.   while ((opt = getopt (argc, argv, "cehinNrs:t:SW")) != -1)
  333.     switch (opt)
  334.     {
  335.       case 'W': UnmountMode = UMNT_READONLY; break;
  336.       case 'S': UseShutdownLibFlag = 1; break;
  337.       case 'R': UnmountMode = UMNT_REMOUNT; break;
  338.       case 'n': AbortableFlag = 0; break;
  339.       case 'r': HaltFlag = HFLG_REBOOT; break;
  340.       case 'h': HaltFlag = HFLG_HALT; break;
  341.       case 'e': HaltFlag = HFLG_EXIT; break;      
  342.       case 't': shutdown_time = atoi (optarg); break;
  343.       case 's': SyncTime = atoi (optarg); break;
  344.       case 'c': cancel_flag = 1; break;
  345.       case 'i': shutdown_time = 0; break;
  346.       default:
  347.         printf ("Usage: %s [-cehinNrSW] [-t <time>] [-s <sync time>].\n", argv[0]);
  348.     exit (EXIT_FAILURE);
  349.     }
  350.  
  351.   /*** Libraries ***/
  352.  
  353.   if (HaltFlag)
  354.     IntuitionBase = (struct IntuitionBase *) OpenLibrary ("intuition.library", 37);
  355.   if (!(QueueBase = OpenLibrary ("queue.library", 0)))
  356.     CleanUp ("Failed to open queue.library.\n");
  357.   if (UseShutdownLibFlag)
  358.   {
  359.     if (!(ShutdownBase = OpenLibrary ("shutdown.library", 0)))
  360.       CleanUp ("Failed to open shutdown.library.\n");
  361.   }
  362.  
  363.   /*** Cancel shutdown ***/
  364.  
  365.   if (cancel_flag)
  366.     CancelRunningShutdown ();
  367.  
  368.   /*** Remount ***/
  369.  
  370.   if (UnmountMode == UMNT_REMOUNT)
  371.   {
  372.     Unmount (NULL, UnmountMode);
  373.     CleanUp ("Filesystems remounted.\n");
  374.   }
  375.  
  376.   /*** Shutdown queue ***/
  377.  
  378.   if ((QueueSignal = AllocSignal (-1)) == -1)
  379.     CleanUp (CantAllocatePort);
  380.   QueueMask = 1 << QueueSignal;
  381.   if (!(ShutdownHandle = QOpen ("shutdown", QMODE_SEND, QueueSignal)))
  382.   {
  383.     FreeSignal (QueueSignal);
  384.     CleanUp ("Failed to open shutdown queue.\n");
  385.   }
  386.  
  387.   /**** Timer device ***/
  388.  
  389.   if (!(TimerPort = CreateMsgPort ()))
  390.     CleanUp (CantAllocatePort);
  391.   if (!(TimerReq = (struct timerequest *)
  392.       CreateIORequest (TimerPort, sizeof (struct timerequest))))
  393.     CleanUp (OutOfMemory);
  394.   if (TimerErr = OpenDevice (TIMERNAME, UNIT_VBLANK, (struct IORequest *) TimerReq, 0))
  395.     CleanUp ("Can't open timer device.\n");
  396.   TimerMask = 1 << TimerPort -> mp_SigBit;
  397.  
  398.   /*** Don't start shutdown twice ***/
  399.  
  400.   Forbid ();
  401.   if (FindPort (ShutdownPortname))
  402.   {
  403.     Permit ();
  404.     CleanUp ("Shutdown is already running.\n");
  405.   }
  406.   Permit ();
  407.  
  408.   /*** Named message port ***/
  409.  
  410.   if (!(ShutdownPort = CreateMsgPort ()))
  411.     CleanUp (CantAllocatePort);
  412.   if (!(ShutdownPort -> mp_Node.ln_Name =
  413.     AllocMem (SpNameLen = strlen (ShutdownPortname) + 1, MEMF_PUBLIC)))
  414.     CleanUp (OutOfMemory);
  415.   bcopy (ShutdownPortname, ShutdownPort -> mp_Node.ln_Name, SpNameLen);
  416.   ShutdownPort -> mp_Node.ln_Pri = 0;
  417.   AddPort (ShutdownPort);
  418.   ShutdownMask = 1 << ShutdownPort -> mp_SigBit;
  419.  
  420.   /*** Shutdown interval loop ***/
  421.  
  422.   WaitMask = QueueMask | ShutdownMask | TimerMask | SIGBREAKF_MASK;
  423.  
  424.   while (shutdown_time >= 10)
  425.   {
  426.     GoingDownMessage (shutdown_time);
  427.     BroadcastShutdownMsg (SHUTDOWN_WARN, shutdown_time);
  428.     shutdown_interval = shutdown_time / 3;
  429.     shutdown_time -= shutdown_interval;
  430.     if (rest = shutdown_time % 5)
  431.     {
  432.       shutdown_interval += rest;
  433.       shutdown_time -= rest;
  434.     }
  435.     AbortableDelay (shutdown_interval);
  436.   }
  437.   GoDown (shutdown_time);
  438. }
  439.  
  440. int
  441. GoDown (int time)
  442. {
  443.   struct EasyStruct es = {
  444.     sizeof (struct EasyStruct), 0, "AmigaDOS", "The system is halted", "Ok"
  445.   };
  446.   ShutdownMessage *smo, *smi;
  447.   ULONG mask;
  448.  
  449.   if (UseShutdownLibFlag)
  450.   {
  451.     Shutdown (SHUTDOWN_EXTERN);
  452.   }
  453.  
  454.   if (time)
  455.   {
  456.     /* last warning */
  457.     GoingDownMessage (time);
  458.     BroadcastShutdownMsg (SHUTDOWN_NOW, time);
  459.     AbortableDelay (time);
  460.  
  461.     /* too late for writing */
  462.     BroadcastShutdownMsg (SHUTDOWN_UMOUNT, 0);
  463.   }
  464.   point_of_no_return = 1;
  465.  
  466.   printf ("The system is going down, unmounting filesystems.\n");
  467.   Unmount (NULL, UnmountMode);
  468.   AbortableDelay (SyncTime);
  469.  
  470.   /*** all done, who turns off the light? ***/
  471.   if (time && HaltFlag != HFLG_EXIT)
  472.   {
  473.     smo = BroadcastShutdownMsg (SHUTDOWN_HALT, 0);
  474.  
  475.     TimerReq -> tr_node.io_Command = TR_ADDREQUEST;
  476.     TimerReq -> tr_time.tv_secs  = 5;
  477.     TimerReq -> tr_time.tv_micro = 0;
  478.     SendIO ((struct IORequest *) TimerReq);
  479.  
  480.     for (;;) /*** Wait for the last broadcast to be replied ***/
  481.     {
  482.       mask = Wait (TimerMask | QueueMask);
  483.       if (mask & QueueMask)
  484.         while (smi = (ShutdownMessage *) QGetMsg (ShutdownHandle))
  485.         {
  486.       if (smi == smo)
  487.         mask |= TimerMask;
  488.           FreeMem (smi, sizeof (ShutdownMessage));
  489.         }
  490.       if (mask & TimerMask)
  491.     break;
  492.     }
  493.   }
  494.   switch (HaltFlag)
  495.   {
  496.     case HFLG_HALT:
  497.       printf ("The system is halted.\n");
  498.       if (IntuitionBase)
  499.         BuildEasyRequest (NULL, &es, NULL);
  500.       Delay (10); /* wait 0.5 seconds */
  501.       Disable ();
  502.       while (1);
  503.     case HFLG_REBOOT:
  504.       ColdReboot ();
  505.     case HFLG_EXIT:
  506.       CleanUp ("Done.\n");
  507.   }
  508. }
  509.